using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using FwkLight.Application.Caching;
using FwkLight.CodeExtensions;
using FwkLight.Domain;
using FwkLight.Domain.Repository;
using FwkLight.Persistence;
using NHibernate.Linq;
using StructureMap;
using NHibernate;

namespace Tody.Core
{
  public class DomainDefinition
  {
    public static T Get<T>(int id) where T : new()
    {
      var typeOfT = typeof (T);
      var cache = ObjectFactory.GetInstance<CacheItemDictionary>();

      var list = cache.Get(new ItemKey<IList<T>>(typeOfT.Name));

      if (list == null)
      {
        //IBaseRepo<T> repo = ObjectFactory.GetInstance<IBaseRepo<T>>();
        var sessionSource = ObjectFactory.GetInstance<ISessionSource>();
        var session = sessionSource.CreateSession();
        var queryable = (from item in session.Linq<T>()
                         select item);
        list = queryable.ToList();
        cache.Add(new ItemKey<IList<T>>(typeOfT.Name), list, 1);
      }

      T definition = (from item in list
                     where ReflectionHelper.GetPropertyValue<int>(item, DomainConstants.IdPartialName) == id
                     select item).First();

      return definition;
    }

    public static ReturnType Get<EntityType, KeyType, ReturnType>(Expression<Func<EntityType, ReturnType>> valueProperty, Expression<Func<EntityType, KeyType>> keyProperty, KeyType keyValue) where EntityType : new()
    {
      var typeOfT = typeof(EntityType);
      var cache = ObjectFactory.GetInstance<CacheItemDictionary>();

      var list = cache.Get(new ItemKey<IList<EntityType>>(typeOfT.Name));

      if (list == null)
      {
        var sessionSource = ObjectFactory.GetInstance<ISessionSource>();
        var session = sessionSource.CreateSession();
        var queryable = (from item in session.Linq<EntityType>()
                         select item);
        list = queryable.ToList();
        cache.Add(new ItemKey<IList<EntityType>>(typeOfT.Name), list, 1);
      }

      MemberInfo vpMember = ((MemberExpression)valueProperty.Body).Member;
      string valuePropertyName = vpMember.Name;

      MemberInfo keyMember = ((MemberExpression)keyProperty.Body).Member;
      string keyPropertyName = keyMember.Name;

      EntityType definition = (from item in list
                               where ReflectionHelper.GetPropertyValue<KeyType>(item, keyPropertyName).Equals(keyValue)
                      select item).First();

      return ReflectionHelper.GetPropertyValue<ReturnType>(definition, valuePropertyName);
    }

    public static T GetEnum<T>(int id) where T : new()
    {
      return (T)Enum.ToObject(typeof(T), id); ;
    }

    public static T GetEnum<T> ( object value) where T : new()
    {
      if(value == null) return default(T);
      return (T)Enum.Parse(typeof(T),value.ToString(),true);
    }
  }
}